package com.reebake.ideal.jdbc;

import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;

import javax.sql.DataSource;
import java.sql.DatabaseMetaData;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

/**
 * 路径处理器，替换{vendor}
 */
public class JdbcLocationResolver {
    private static final String VENDOR_PLACEHOLDER = "{vendor}";
    private final DataSource dataSource;

    public JdbcLocationResolver(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public List<String> resolveLocations(List<String> locations) {
        if (this.usesVendorLocation(locations)) {
            DatabaseDriver databaseDriver = this.getDatabaseDriver();
            return this.replaceVendorLocations(locations, databaseDriver);
        } else {
            return locations;
        }
    }

    private List<String> replaceVendorLocations(List<String> locations, DatabaseDriver databaseDriver) {
        if (databaseDriver == DatabaseDriver.UNKNOWN) {
            return locations;
        } else {
            String vendor = databaseDriver.getId();
            return locations.stream().map((location) -> {
                return location.replace("{vendor}", vendor);
            }).toList();
        }
    }

    private DatabaseDriver getDatabaseDriver() {
        try {
            String url = (String) JdbcUtils.extractDatabaseMetaData(this.dataSource, DatabaseMetaData::getURL);
            return DatabaseDriver.fromJdbcUrl(url);
        } catch (MetaDataAccessException var2) {
            throw new IllegalStateException(var2);
        }
    }

    private boolean usesVendorLocation(Collection<String> locations) {
        Iterator var2 = locations.iterator();

        String location;
        do {
            if (!var2.hasNext()) {
                return false;
            }

            location = (String)var2.next();
        } while(!location.contains("{vendor}"));

        return true;
    }
}
